package edu.chalmers.targine;

import java.util.ArrayList;

import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.opengl.GLUtils;
import edu.dhbw.andar.ARObject;

public class Arbject extends ARObject {
	public boolean hasModel = false;
	
	public boolean dirty = false;
	
	protected boolean resetModels = false;
	private String name;
	private String patternID;
	private String nfcID;
	protected String value;
	private double markerWidth;
	private double[] center;
	
	protected ArrayList<Mesh> newMeshes = new ArrayList<Mesh>();
	protected ArrayList<Mesh> meshes = new ArrayList<Mesh>();
	protected ArrayList<Billboard> billboards = new ArrayList<Billboard>();
	protected ArrayList<TextBillboard> textBillboards = new ArrayList<TextBillboard>();
	
	protected Context mContext;
	
	public Arbject(String name, String patternID, String nfcID, Context context) {
		super(name, patternID, 80, new double[]{0,0});
		
		this.name = name;
		this.patternID = patternID;
		this.nfcID = nfcID;
		this.markerWidth = 80;
		this.center = new double[]{0,0};
		mContext = context;
		
		value = "none";
	}
	
//	public void addSkier(Model model, String modelName){
//		//TODO: remove the old local skier
//		model.finalize();
//		model = new Model(model, modelName);
//		
//		synchronized(newSkiers){
//			removeLocalSkier = false;
//			localSkier = new Skier(model, levelParts, localSkierID);
//			newSkiers.add(localSkier);
//		}
//		markForReinitialization();
//	}
//	
//	public void changeSkierAngle(float da){
//		if(localSkier != null){
//			localSkier.setAngle(da);
//		}
//	}
	
//	public void setValue(String var, String value){
//		if(var.equals("LEVEL")){
////			setLevel(value.split(","));
//			this.value = value;
//			updateLevel();
//		}
//		else if(var.equals("PLAYER")){
//			String[] parsedPlayer = value.split("&");
//			if(parsedPlayer[1].equals("none")){
//				//remove skier
//				removeSkier(Integer.parseInt(parsedPlayer[0]));
//			} else{
//				//update skier
//				updateSkier(Integer.parseInt(parsedPlayer[0]), 
//							Float.parseFloat(parsedPlayer[1]), 
//							Float.parseFloat(parsedPlayer[2]));
//			}
//		}
//	}
	
//	public void removeSkier(int id){
//		if(skiers.containsKey(""+id)){
//			//remove non-local skier
//			synchronized (removeSkierIDs){
//				removeSkierIDs.add(new Integer(id));
//			}
//			markForReinitialization();
//		}
//	}
//	
//	public void updateSkier(int id, float xpos, float ypos){
//		if(skiers.containsKey(""+id)){
//			//update non-local skier
//			skiers.get(""+id).setPosition(xpos, ypos, 0f);
//		} else if(localSkierID == id){
//			//what do?
//		} else{
//			Model newSkierModel = ARManager.models.get("skier");
//			newSkierModel.finalize();
//			newSkierModel = new Model(newSkierModel, "skier");
//			Skier newSkier = new Skier(newSkierModel, levelParts, id);
//			newSkier.setPosition(xpos, ypos, 0f);
//			newSkiers.add(newSkier);
//			markForReinitialization();
//		}
//	}
	
//	public void setPlayer(String[] parsedSkier){
//		int id = Integer.parseInt(parsedSkier[0]);
//		if(id == localSkierID){
//			return;
//		}
//		
//		float xpos = Float.parseFloat(parsedSkier[1]);
//		float ypos = Float.parseFloat(parsedSkier[2]);
//		
//		if(skiers.isEmpty()){
//			Model model = CustomActivity.models.get("skier");
//			model.finalize();
//			model = new Model(model, "skier");
//			model.xpos = xpos;
//			model.ypos = ypos;
//			synchronized(newSkiers){
//				newSkiers.add(new Skier(model, levelParts, id));
//			}
//			markForReinitialization();
//			return;
//		}
//		
//		//TODO: fix so it works for many skiers
////		updateSkierWithID(xpos, ypos);
//		updateSkierWithID(id, xpos, ypos);
//	}
	
//	public void updateSkierWithID(int id, float xpos, float ypos){
//		skiers.get(""+id).setPosition(xpos, ypos, 0f);
////		for(Skier skier : skiers){
////			if(skier.hasID(id)){
////				skier.setPosition(xpos, ypos, 0);
////			}
////		}
//	}
	
//	public void addLevelPart(String partType){
//		if(value.equals("none")){
//			value = "";
//		}
//		
//		if(ARManager.models.containsKey(partType)){
//			value += "," + partType;
//		} else{
//			value += ",none";
//		}
//		
//		if(value.charAt(0) == ','){
//			value = value.substring(1);
//		}
//		updateLevel();
//	}
//	
//	public void setLevel(String[] newValue){
//		String tmpValue = "";
//		for(int i = 0; i < newValue.length; i++){
//			if(ARManager.models.containsKey(newValue[i])){
//				tmpValue += "," + newValue[i];
//			} else{
//				tmpValue += ",none";
//			}
//		}
//		if(tmpValue.charAt(0) == ','){
//			tmpValue = tmpValue.substring(1);
//		}
//		value = tmpValue;
//		updateLevel();
//	}
	
//	public void updateLevel(){
//		String[] parsedValue = value.split(",");
//		if(parsedValue[0].equals("none")){
//			//welcome to die§
//			clearLevel();
//		} else{
//			for(int i = 0; i < parsedValue.length; i++){
//				if(ARManager.models.containsKey(parsedValue[i])){
//					if(i >= levelParts.size()){
//						//add levelPart
//						hasModel = true;
//						Model newModel = ARManager.models.get(parsedValue[i]);
//						newModel.finalize();
//						newModel = new Model(newModel, parsedValue[i]);
//						
//						if(levelParts.size() == 0){
//							newModel.xpos = i * 80f;
//						}
//						else{
//							updateCoordinatesAndDirection(levelParts.get(levelParts.size() - 1));
//							newModel.xpos = nextX;
//							newModel.ypos = nextY;
//						}
//						
//						synchronized(newLevelParts){
//							if(newLevelParts.size() == 0){
//								newLevelParts.addAll(levelParts);
//							}
//							newLevelParts.add(new LevelPart(newModel, parsedValue[i]));
//						}
//					} else{
//						//change level part at this index
//						hasModel = true;
//						Model newModel = ARManager.models.get(parsedValue[i]);
//						newModel.finalize();
//						newModel = new Model(newModel, parsedValue[i]);
//						
//						if(i == 0){
//							newModel.xpos = i * 80f;
//						}
//						else{
//							updateCoordinatesAndDirection(levelParts.get(i - 1));
//							newModel.xpos = nextX;
//							newModel.ypos = nextY;
//						}
//
//						synchronized(newLevelParts){
//							if(newLevelParts.size() == 0){
//								newLevelParts.addAll(levelParts);
//							}
//							newLevelParts.set(i, new LevelPart(newModel, parsedValue[i]));
//						}
//					}
//				}
//				//no diff, do nothing
//			}
//		}
//		dirty = false;
//		markForReinitialization();
//	}
	
//	private void updateCoordinatesAndDirection(LevelPart previousLevelPart){
//		switch(previousLevelPart.getDirection()){
//			case LevelPart.DIRECTION_FORWARD:
//				nextX = previousLevelPart.getXPos() + 80f;
//				nextY = previousLevelPart.getYPos();
//				break;
//			case LevelPart.DIRECTION_LEFT:
//				nextX = previousLevelPart.getXPos();
//				nextY = previousLevelPart.getYPos() + 80f;
//				nextDirection = (nextDirection + 1) % 2;
//				break;
//			case LevelPart.DIRECTION_RIGHT:
//				nextX = previousLevelPart.getXPos();
//				nextY = previousLevelPart.getYPos() - 80f;
//				if(nextDirection-- < 0){
//					nextDirection = 2;
//				}
//				break;
//		}
//	}
	
//	private int getDirection(){
////		return newLevelParts.size() == 0 ? LevelPart.DIRECTION_FORWARD : 
////			   newLevelParts.get(newLevelParts.size() - 1).getDirection();
//		return newLevelParts.get(newLevelParts.size() - 1).getDirection();
//	}
	
//	private float getPreviousXPos(){
////		return newLevelParts.size() == 0 ? 0f : 
////			   newLevelParts.get(newLevelParts.size() - 1).getXPos();
//		return newLevelParts.get(newLevelParts.size() - 1).getXPos();
//	}
//	
//	private float getPreviousYPos(){
////		return newLevelParts.size() == 0 ? 0f : 
////			   newLevelParts.get(newLevelParts.size() - 1).getYPos();
//		return newLevelParts.get(newLevelParts.size() - 1).getYPos();
//	}

	@Override
	public void init(GL10 gl){
		if(resetModels){
			clear();
		}
		
		synchronized(newMeshes){
			if(!newMeshes.isEmpty()){
				meshes.addAll(newMeshes);
				newMeshes = new ArrayList<Mesh>();
			}
		}
		
		for(Mesh mesh : meshes){
			mesh.init(gl);
		}
		
		for(TextBillboard tb: textBillboards){
			if(tb.isUninitialised()){
				tb.init(gl);
			}
		}
	}

	@Override
	public synchronized void draw(GL10 gl){
		super.draw(gl);
		
		for(Mesh mesh : meshes){
			if(mesh.isFinalized() && mesh.hasModel()){
				mesh.draw(gl);
			}
		}
		
		for(Mesh mesh: meshes){
			mesh.update();
		}
		
		for(Billboard bb : billboards){
			bb.draw(gl);
		}
		
		for(TextBillboard tb : textBillboards){
			tb.draw(gl);
		}
	}
	
//	public void removeLocalPlayer(){
//		localSkier = null;
//		removeLocalSkier = false;
//	}
//	
//	public boolean isLocalPlayerMarkedForRemoval(){
//		return removeLocalSkier;
//	}
//	
//	public boolean hasLocalPlayer(){
//		return localSkier != null;
//	}
//	
//	public String getPlayerValue(){
//		return localSkier.getID() + "&" + localSkier.getXPos() + "&" + localSkier.getYPos();
//	}
//	
//	public String getRemovePlayerValue(){
//		return localSkier.getID() + "&" + "none";
//	}
	
	// Will load a texture out of a drawable resource file, and return an OpenGL texture ID:
		protected int loadTexture(GL10 gl, Context context, int resource) {
		    // In which ID will we be storing this texture?
			int[] tempTex = new int[1];
			gl.glGenTextures(1, tempTex, 0);
		    int id = tempTex[0];
		    
		    // We need to flip the textures vertically:
		    Matrix flip = new Matrix();
		    flip.postScale(1f, -1f);
		    
		    // This will tell the BitmapFactory to not scale based on the device's pixel density:
		    // (Thanks to Matthew Marshall for this bit)
		    BitmapFactory.Options opts = new BitmapFactory.Options();
		    opts.inScaled = false;
		    
		    // Load up, and flip the texture:
		    Bitmap temp = BitmapFactory.decodeResource(context.getResources(), resource, opts);
		    Bitmap bmp = Bitmap.createBitmap(temp, 0, 0, temp.getWidth(), temp.getHeight(), flip, true);
		    temp.recycle();
		    
		    gl.glBindTexture(GL10.GL_TEXTURE_2D, id);
		    
		    // Set all of our texture parameters:
		    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR_MIPMAP_NEAREST);
		    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR_MIPMAP_NEAREST);
		    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
		    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
		    
		    // Generate, and load up all of the mipmaps:
		    for(int level=0, height = bmp.getHeight(), width = bmp.getWidth(); true; level++) {
		        // Push the bitmap onto the GPU:
		        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, level, bmp, 0);
		        
		        // We need to stop when the texture is 1x1:
		        if(height==1 && width==1) break;
		        
		        // Resize, and let's go again:
		        width >>= 1; height >>= 1;
		        if(width<1)  width = 1;
		        if(height<1) height = 1;
		        
		        Bitmap bmp2 = Bitmap.createScaledBitmap(bmp, width, height, true);
		        bmp.recycle();
		        bmp = bmp2;
		    }
		    
		    bmp.recycle();
		    
		    return id;
		}
		
		public void clear(){
			value = "none";
			hasModel = false;
			meshes.clear();
			billboards.clear();
			textBillboards.clear();
			resetModels = false;
		}
		
		public void addBillboard(int texID, float x, float y, float z, float scale, float xRot){
			billboards.add(new Billboard(texID, x, y, z, scale, xRot));
		}
		
		public void addTextBillboard(TextBillboard textBillboard){
			textBillboards.add(textBillboard);
		}
		
		public void addMesh(Mesh mesh){
			newMeshes.add(mesh);
			markForReinitialization();
		}
		
		public String getName(){
			return name;
		}
		
		public String getPatternID(){
			return patternID;
		}
		
		public String getID(){
			return nfcID;
		}
		
		public double getMarkerWidth(){
			return markerWidth;
		}
		
		public double[] getCenter(){
			return center;
		}
		
		public String getValue(){
			return value;
		}
}
